home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CM / CMDbgOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  29.6 KB  |  843 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:         CMDbgOps.c 
  3.  
  4.     Contains:    Container Manager Debugging Operations
  5.  
  6.     Written by:    Ira L. Ruben
  7.  
  8.     Owned by:    Ed Lai
  9.  
  10.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.          <2>     1/15/96    TJ        Cleaned Up
  15.          <3>     12/9/94    EL        #1182275 Optionally do not maintain
  16.                                     continue flag.
  17.          <2>     8/26/94    EL        #1181622 Ownership update
  18.          <1>      2/3/94    EL        first checked in
  19.          <2>    11/23/93    EL        When updating save TOC data so that TOC
  20.                                     don't need to be read twice.
  21.  
  22.     To Do:
  23. */
  24.  
  25. /*---------------------------------------------------------------------------*
  26.  |                                                                           |
  27.  |                           <<<  CMDbgOps.c  >>>                            |
  28.  |                                                                           |
  29.  |                  Container Manager Debugging Operations                   |
  30.  |                                                                           |
  31.  |                               Ira L. Ruben                                |
  32.  |                                 4/23/92                                   |
  33.  |                                                                           |
  34.  |                    Copyright Apple Computer, Inc. 1992-1994               |
  35.  |                           All rights reserved.                            |
  36.  |                                                                           |
  37.  *---------------------------------------------------------------------------*
  38.  
  39.  This file defines a set of special debugging API routines.  They are kept separate from
  40.  the API (and undocumented) since they may or may not be supported in a particular
  41.  installation.
  42.  
  43.  There are three routines:
  44.  
  45.      1. CMDebugging()                    - to set some internal debugging "options"
  46.     2. CMDumpTOCStructures()    - to dump in-memory TOC as a tree-like format
  47.     3. CMDumpContainerTOC()        - to read in container TOC and display it in a table format
  48.  
  49.  The CMDebugging() routine is under control of the CMDEBUGGING switch macro.  The 
  50.  installer may suppress this functionality by setting this macro to 0 (its default).
  51.  
  52.  Similarly, the other routines are under control of the CMDUMPTOC switch.
  53.  
  54.  The switches are defined in CMTypes.h.
  55. */
  56.  
  57.  
  58. #include <stddef.h>
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include <stdarg.h>
  62. #include <limits.h>
  63.  
  64. #ifndef __CMTYPES__
  65. #include "CMTypes.h"
  66. #endif
  67. #ifndef __CM_API_DEBUG__
  68. #include "CMAPIDbg.h"
  69. #endif
  70. #ifndef __CM_API__
  71. #include "CMAPI.h"
  72. #endif
  73. #ifndef __LISTMGR__
  74. #include "ListMgr.h"
  75. #endif
  76. #ifndef __TOCENTRIES__
  77. #include "TOCEnts.h"   
  78. #endif
  79. #ifndef __TOCOBJECTS__
  80. #include "TOCObjs.h"   
  81. #endif
  82. #ifndef __TOCIO__
  83. #include "TOCIO.h"
  84. #endif
  85. #ifndef __CONTAINEROPS__
  86. #include "Containr.h"  
  87. #endif
  88. #ifndef __HANDLERS__
  89. #include "Handlers.h"
  90. #endif
  91. #ifndef __UPDATING__
  92. #include "Update.h"  
  93. #endif
  94. #ifndef __REFERENCES__
  95. #include "Refs.h"      
  96. #endif
  97. #ifndef __ERRORRPT__
  98. #include "ErrorRpt.h"      
  99. #endif
  100. #ifndef __SESSIONDATA__
  101. #include "Session.h"          
  102. #endif
  103. #ifndef __UTILITYROUTINES__
  104. #include "Utility.h"        
  105. #endif
  106.  
  107.                                                                     CM_CFUNCTIONS
  108.  
  109. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  110. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  111. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  112. /* choke compilers that don't recognize them.                                                                                      */
  113.  
  114. #if CM_MPW
  115. #pragma segment Debugging
  116. #endif
  117.  
  118.  
  119. #if CMDEBUGGING || CMDUMPTOC
  120. /*------------------------------*
  121.  | display - isolate all output |
  122.  *------------------------------*
  123.  
  124.  In some environments it may be more desirable (or necessary) to handle I/O specially. To
  125.  that end this routine is provided.  All the debug printing goes through  here.  It's
  126.  parameters are identical to fprintf(), with the same meaning.  So, as delivered, in its
  127.  simplest form, this routine maps into a fprintf().  Feel free to "warp" this routine into
  128.  somthing appropriate to your system.
  129. */
  130.  
  131. static void CM_NEAR CM_C display(FILE *stream, const CM_CHAR *format, ...)
  132. {
  133.     va_list ap;
  134.     
  135.     va_start(ap, format);
  136.     vfprintf(stream, format, ap);
  137.     va_end(ap);
  138. }
  139. #endif
  140.  
  141.  
  142. #if CMDEBUGGING
  143. /*------------------------------------------------*
  144.  | CMDebugging - set internal debugging "options" |
  145.  *------------------------------------------------*
  146.  
  147.  This is an undocumented (except for what you're reading now) routine to allow me 
  148.  to do some debugging.  It is called AFTER 
  149.  CMStartSession() but BEFORE any containers are opened.  It takes the session global data
  150.  pointer returned by CMStartSession() and adds (actually modifies) some of the data there
  151.  to enable debugging.
  152.  
  153.  The current data that can be set is:
  154.  
  155.          1. The size of the TOC index tables.  If 0 is passed, the default is used.  The
  156.              current implementation of the TOC uses an index table mechanism with the tables
  157.              each being tocTableSize entries long.  See  TOCObjs.c   and .h for further details.
  158.         
  159.         2. A FILE* debugging output variable.  It is usually stdout, stderr, or NULL.  For NULL
  160.              no debugging output is produced.  Currently this thing is used to display the TOC as
  161.              a table when it is open for input.
  162.              
  163.         3. The dynamic switch controlling the refNum validations (e.g., checking for NULL) and
  164.              various other protections.  If set to 0 the protection checks are suppressed.  If
  165.              nonzero they are performed, but only if the protection code is present.  On a per-
  166.              installation basis it may be suppressed.  In that case the switch has no effect.
  167.  
  168.  The entire routine may be suppressed, which it is by default, by setting the macro
  169.  variable CMDEBUGGING to 0.
  170. */
  171.  
  172. void CM_FIXEDARGS CMDebugging(CMSession sessionData, CM_USHORT tocTableSize, 
  173.                                                             FILE CM_PTR *debuggingFile, CMBoolean doValidations)
  174. {
  175.     CM_CHAR s1[10], s2[10];
  176.     #if !CMVALIDATE
  177.     CMBoolean unused = doValidations;
  178.     #endif
  179.     
  180.     if (sessionData != NULL) {
  181.         ((SessionGlobalDataPtr)sessionData)->cmDbgFile        = debuggingFile;                            
  182.         ((SessionGlobalDataPtr)sessionData)->cmTocTblSize = (CM_ULONG)tocTableSize;
  183.         
  184.         if (tocTableSize == 0)
  185.             ((SessionGlobalDataPtr)sessionData)->cmTocTblSize = DefaultIndexTableSize;
  186.         else if (tocTableSize < MinIndexTableSize || tocTableSize > MaxIndexTableSize) {
  187.             SessionERROR2(CM_err_BadTocSize, cmltostr(MinIndexTableSize, 1, false, s1),
  188.                                                                               cmltostr(MaxIndexTableSize, 1, false, s2));
  189.             ((SessionGlobalDataPtr)sessionData)->cmTocTblSize = DefaultIndexTableSize;
  190.         }
  191.         
  192.         #if CMVALIDATE
  193.         ((SessionGlobalDataPtr)sessionData)->validate = doValidations;
  194.         #endif
  195.     }
  196. }
  197. #endif
  198.  
  199.  
  200. #if CMDUMPTOC
  201. /*----------------------------------------------------*
  202.  | showTouchedList - display an object's touched list |
  203.  *----------------------------------------------------*
  204.  
  205.  This is called by showObject() if there is a updating touch list for that object.  The
  206.  entire touch list is displayed.
  207. */
  208.  
  209. static void showTouchedList(TouchedListEntryPtr touch, CMRefCon refCon)
  210. {
  211.     FILE                      *f = (FILE *)refCon;
  212.     CM_USHORT             i, mask, touchFlags;
  213.     CM_CHAR               flagsMeaning[256];
  214.     
  215.     display(f, "\n                           --- Touched List ---\n");
  216.     
  217.     while (touch) {
  218.         touchFlags = touch->touchFlags;
  219.         
  220.         if (touchFlags == 0x0000U) 
  221.             *flagsMeaning = '\0';
  222.         else {
  223.             strcpy(flagsMeaning, " (");
  224.             
  225.             for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) {
  226.                 if ((touchFlags & mask) == TouchedRemoved) {
  227.                     strcat(flagsMeaning, "TouchedRemoved/");
  228.                     continue;
  229.                 }
  230.                 if ((touchFlags & mask) == TouchedInserted) {
  231.                     strcat(flagsMeaning, "TouchedInserted/");
  232.                     continue;
  233.                 }
  234.                 if ((touchFlags & mask) == TouchedDeletedValue) {
  235.                     strcat(flagsMeaning, "TouchedDeletedValue/");
  236.                     continue;
  237.                 }
  238.                 if ((touchFlags & mask) == TouchedDeletedProperty) {
  239.                     strcat(flagsMeaning, "TouchedDeletedProperty/");
  240.                     continue;
  241.                 }
  242.                 if ((touchFlags & mask) == TouchedEdited) {
  243.                     strcat(flagsMeaning, "TouchedEdited/");
  244.                     continue;
  245.                 }
  246.                 if ((touchFlags & mask) == TouchedImmediate) {
  247.                     strcat(flagsMeaning, "TouchedImmediate/");
  248.                     continue;
  249.                 }
  250.                 if ((touchFlags & mask) == TouchedBaseType) {
  251.                     strcat(flagsMeaning, "TouchedBaseType/");
  252.                     continue;
  253.                 }
  254.                 if ((touchFlags & mask) == TouchedSetinfoed) {
  255.                     strcat(flagsMeaning, "TouchedSetinfoed/");
  256.                     continue;
  257.                 }
  258.             } /* for */
  259.             
  260.             strcpy(flagsMeaning + strlen(flagsMeaning) - 1, ")");
  261.         }
  262.         
  263.         display(f, "\n            0x%.8lX: theValueHdr  = 0x%.8lX\n"
  264.                              "                        touchFlags     = 0x%.4lX%s\n"
  265.                              "                        OPT          = 0x%.8lX/0x%.8lX/0x%.8lX = %ld/%ld/%ld\n"
  266.                              "                        removedEntry = 0x%.8lX\n",
  267.                              touch,
  268.                              touch->theValueHdr,
  269.                              touch->touchFlags, flagsMeaning,
  270.                              touch->objectID, touch->propertyID, touch->typeID, touch->objectID, touch->propertyID, touch->typeID,
  271.                              touch->removedEntry);
  272.         
  273.         touch = (TouchedListEntryPtr)cmGetNextListCell(touch);
  274.     } /* while */
  275.     
  276.     display(f, "\n                        --- end of touched list ---\n");
  277. }
  278.  
  279.  
  280. /*-----------------------------------------------------------------*
  281.  | showObject - action routine for displaying an object in the TOC |
  282.  *-----------------------------------------------------------------*
  283.  
  284.  This is a debugging routine used as the "action" parameter to cmWalkThroughEntireTOC()
  285.  calls to display selected info for an object in the TOC. The "refCon" here is expected to
  286.  be a file variable.
  287.  
  288.  Note, this "static" is intentionally left to default memory model under DOS since it is
  289.  passed as a function pointer to cmWalkThroughEntireTOC().
  290. */
  291.  
  292. static TOCWalkReturns showObject(ContainerPtr container, TOCObjectPtr theObject, CMRefCon refCon)
  293. {
  294.     ContainerPtr      unused = container;
  295.     FILE                      *f = (FILE *)refCon;
  296.     CM_USHORT             i, mask, objectFlags;
  297.     CM_CHAR               flagsMeaning[256];
  298.     
  299.     objectFlags  = theObject->objectFlags;
  300.     
  301.     if (objectFlags == 0x0000U) 
  302.         *flagsMeaning = '\0';
  303.     else {
  304.         strcpy(flagsMeaning, " (");
  305.         
  306.         for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) {
  307.             if ((objectFlags & mask) == UndefinedObject) {
  308.                 strcat(flagsMeaning, "UndefinedObject/");
  309.                 continue;
  310.             }
  311.             if ((objectFlags & mask) == ObjectObject) {
  312.                 strcat(flagsMeaning, "ObjectObject/");
  313.                 continue;
  314.             }
  315.             if ((objectFlags & mask) == PropertyObject) {
  316.                 strcat(flagsMeaning, "PropertyObject/");
  317.                 continue;
  318.             }
  319.             if ((objectFlags & mask) == TypeObject) {
  320.                 strcat(flagsMeaning, "TypeObject/");
  321.                 continue;
  322.             }
  323.             if ((objectFlags & mask) == DeletedObject) {
  324.                 strcat(flagsMeaning, "DeletedObject/");
  325.                 continue;
  326.             }
  327.             if ((objectFlags & mask) == ProtectedObject) {
  328.                 strcat(flagsMeaning, "ProtectedObject/");
  329.                 continue;
  330.             }
  331.             if ((objectFlags & mask) == LinkedObject) {
  332.                 strcat(flagsMeaning, "LinkedObject/");
  333.                 continue;
  334.             }
  335.             if ((objectFlags & mask) == UndefObjectCounted) {
  336.                 strcat(flagsMeaning, "UndefObjectCounted/");
  337.                 continue;
  338.             }
  339.             if ((objectFlags & mask) == DynamicValuesObject) {
  340.                 strcat(flagsMeaning, "DynamicValuesObject/");
  341.                 continue;
  342.             }
  343.         } /* for */
  344.         
  345.         strcpy(flagsMeaning + strlen(flagsMeaning) - 1, ")");
  346.     }
  347.     
  348.     display(f, "---------------------------------------------\nTOCObject\n");
  349.     display(f, "0x%.8lX: objectID          = 0x%.8lX = %ld\n"
  350.                             "            container         = 0x%.8lX (%s) [%d]\n"
  351.                             "            nextObject        = 0x%.8lX\n"
  352.                             "            prevObject        = 0x%.8lX\n"
  353.                             "            nextTypeProperty  = 0x%.8lX\n"
  354.                             "            prevTypeProperty  = 0x%.8lX\n"
  355.                             "            nextTouchedObject = 0x%.8lX\n"
  356.                             "            objectFlags       = 0x%.4X%s\n",
  357.                             theObject,
  358.                             theObject->objectID, theObject->objectID,
  359.                             theObject->container, CONTAINERNAMEx(theObject->container), theObject->container->depth,
  360.                             theObject->nextObject,
  361.                             theObject->prevObject,
  362.                             theObject->nextTypeProperty,
  363.                             theObject->prevTypeProperty,
  364.                             theObject->nextTouchedObject,
  365.                             theObject->objectFlags, flagsMeaning);
  366.                             
  367.     if (!cmIsEmptyList(&theObject->touchedList))
  368.         showTouchedList((TouchedListEntryPtr)cmGetListHead(&theObject->touchedList), refCon);
  369.     
  370.     return (WalkNextTOCProperty);
  371. }
  372.  
  373.  
  374. /*---------------------------------------------------------------------*
  375.  | showProperty - action routine for displaying an property in the TOC |
  376.  *---------------------------------------------------------------------*
  377.  
  378.  This is a debugging routine used as the "action" parameter to cmWalkThroughEntireTOC() 
  379.  calls to display selected info for a property in the TOC. The "refCon" here is expected
  380.  to be a file variable.
  381.  
  382.  Note, this "static" is intentionally left to default memory model under DOS since it is
  383.  passed as a function pointer to cmWalkThroughEntireTOC().
  384. */
  385.  
  386. static TOCWalkReturns showProperty(ContainerPtr container, TOCPropertyPtr theProperty, CMRefCon refCon)
  387. {
  388.     ContainerPtr unused = container;    
  389.     FILE                 *f = (FILE *)refCon;
  390.     
  391.     display(f, "\n            TOCProperty\n"
  392.                          "            0x%.8lX: propertyID = 0x%.8lX = %ld\n"
  393.                          "                        theObject  = 0x%.8lX\n",
  394.                          theProperty,
  395.                          theProperty->propertyID, theProperty->propertyID,
  396.                          theProperty->theObject);
  397.  
  398.     return (WalkNextTOCValueHdr);
  399. }
  400.  
  401.  
  402. /*------------------------------------------------------------------------*
  403.  | showValueHdr - action routine for displaying a value header in the TOC |
  404.  *------------------------------------------------------------------------*
  405.  
  406.  This is a debugging routine used as the "action" parameter to cmWalkThroughEntireTOC()
  407.  calls to display selected info for a value header in the TOC. The "refCon" here is
  408.  expected to be a file variable.
  409.  
  410.  Note, this "static" is intentionally left to default memory model under DOS since it is
  411.  passed as a function pointer to cmWalkThroughEntireTOC().
  412. */
  413.  
  414. static TOCWalkReturns showValueHdr(ContainerPtr container, TOCValueHdrPtr theValueHdr, CMRefCon refCon)
  415. {
  416.     FILE                      *f = (FILE *)refCon;
  417.     CM_USHORT             i, mask, valueFlags;
  418.     CM_CHAR                 *extensions, *refs, *shadowListStatus = "", flagsMeaning[256];
  419.     ContainerPtr      unused = container;
  420.     #if CMSHADOW_LIST
  421.     RefDataShadowEntryPtr r = NULL;
  422.     #endif
  423.     
  424.     valueFlags = theValueHdr->valueFlags;
  425.     
  426.     if (valueFlags & ValueDynamic)
  427.         extensions = "extensions   ";
  428.     else
  429.         extensions = "dynValue     ";
  430.     
  431.     #if CMSHADOW_LIST
  432.     if (HasRefDataObject(theValueHdr))
  433.         refs = "refDataObject";
  434.     else if (theValueHdr->typeID == CM_StdObjID_ObjRefData) {
  435.         refs = "refShadowList";
  436.         if (RefShadowList(theValueHdr) != NULL) {
  437.             r = (RefDataShadowEntryPtr)cmGetListHead(RefShadowList(theValueHdr));
  438.             shadowListStatus = (r == NULL) ? " (<empty>)" : "";
  439.         }
  440.     } else
  441.         refs = "refDataObject";
  442.     #else
  443.     refs = "refDataObject";
  444.     #endif
  445.     
  446. #if !CMKEEP_CONTINUE_FLAG
  447.     if (cmCountListCells(&theValueHdr->valueList) > 1)
  448.         valueFlags |= ValueContinued;
  449.     else
  450.         valueFlags &= ~ValueContinued;
  451. #endif
  452.  
  453.     if (valueFlags == 0x0000U)
  454.         *flagsMeaning = '\0';
  455.     else {
  456.         strcpy(flagsMeaning, " (");
  457.         
  458.         for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) {
  459.             if ((theValueHdr->valueFlags & mask) == ValueDeleted) {
  460.                 strcat(flagsMeaning, "ValueDeleted/");
  461.                 continue;
  462.             }
  463.             if ((theValueHdr->valueFlags & mask) == ValueContinued) {
  464.                 strcat(flagsMeaning, "ValueContinued/");
  465.                 continue;
  466.             }
  467.             if ((theValueHdr->valueFlags & mask) == ValueGlobal) {
  468.                 strcat(flagsMeaning, "ValueGlobal/");
  469.                 continue;
  470.             }
  471.             if ((theValueHdr->valueFlags & mask) == ValueImmediate) {
  472.                 strcat(flagsMeaning, "ValueImmediate/");
  473.                 continue;
  474.             }
  475.             if ((theValueHdr->valueFlags & mask) == ValueOffPropChain) {
  476.                 strcat(flagsMeaning, "ValueOffPropChain/");
  477.                 continue;
  478.             }
  479.             if ((theValueHdr->valueFlags & mask) == ValueDynamic) {
  480.                 strcat(flagsMeaning, "ValueDynamic/");
  481.                 continue;
  482.             }
  483.             if ((theValueHdr->valueFlags & mask) == ValueUndeletable) {
  484.                 strcat(flagsMeaning, "ValueUndeletable/");
  485.                 continue;
  486.             }
  487.             if ((theValueHdr->valueFlags & mask) == ValueProtected) {
  488.                 strcat(flagsMeaning, "ValueProtected/");
  489.                 continue;
  490.             }
  491.             if ((theValueHdr->valueFlags & mask) == ValueDefined) {
  492.                 strcat(flagsMeaning, "ValueDefined/");
  493.                 continue;
  494.             }
  495.         } /* for */
  496.         
  497.         strcpy(flagsMeaning + strlen(flagsMeaning) - 1, ")");
  498.     }
  499.     
  500.     display(f, "\n                        TOCValueHdr\n"
  501.                          "                        0x%.8lX: typeID        = 0x%.8lX = %ld\n"
  502.                          "                                    theProperty   = 0x%.8lX\n"
  503.                          "                                    container     = 0x%.8lX (%s) [%d]\n"
  504.                          "                                    size          = 0x%.8lX = %ld\n"
  505.                          "                                    logicalSize   = 0x%.8lX = %ld\n"
  506.                          "                                    generation    = 0x%.8lX\n",
  507.                          theValueHdr,
  508.                          theValueHdr->typeID, theValueHdr->typeID,
  509.                          theValueHdr->theProperty,
  510.                          theValueHdr->container, CONTAINERNAMEx(theValueHdr->container), theValueHdr->container->depth,
  511.                          theValueHdr->size, theValueHdr->size,
  512.                          theValueHdr->logicalSize, theValueHdr->logicalSize,
  513.                          theValueHdr->generation);
  514.     display(f, "                                    useCount      = 0x%.8lX\n"
  515.                          "                                    valueRefCon   = 0x%.8lX\n"
  516.                          "                                    touch         = 0x%.8lX\n"
  517.                          "                                    %s = 0x%.8lX\n"
  518.                          "                                    %s = 0x%.8lX%s\n"
  519.                          "                                    valueFlags    = 0x%.4X%s\n",
  520.                          theValueHdr->useCount,
  521.                          theValueHdr->valueRefCon,
  522.                          theValueHdr->touch,
  523.                          extensions, DYNEXTENSIONS(theValueHdr),
  524.                          refs, RefDataObject(theValueHdr), shadowListStatus,
  525.                          theValueHdr->valueFlags, flagsMeaning);
  526.     
  527.     if (theValueHdr->valueFlags & ValueDynamic)
  528.         display(f, "                        Extensions: baseValue     = 0x%.8lX\n",
  529.                              DYNEXTENSIONS(theValueHdr)->baseValue);
  530.     
  531.     #if CMSHADOW_LIST
  532.     if (r != NULL) {
  533.         display(f, "\n                                                    Key      Object ID\n"
  534.                              "                        Shadow List: 0x%.8lX: 0x%.8lX  0x%.8lX = %ld\n",
  535.                              r, r->key, r->objectID, r->objectID);
  536.         r = (RefDataShadowEntryPtr)cmGetNextListCell(r);
  537.         if (r == NULL)
  538.             display(f, "                        0x%.8lX\n", RefShadowList(theValueHdr));
  539.         else {
  540.             display(f, "                        0x%.8lX   0x%.8lX: 0x%.8lX  0x%.8lX = %ld\n",
  541.                                  RefShadowList(theValueHdr), r, r->key, r->objectID, r->objectID);
  542.             r = (RefDataShadowEntryPtr)cmGetNextListCell(r);
  543.         }
  544.         while (r) {
  545.             display(f, "                                     0x%.8lX: 0x%.8lX  0x%.8lX = %ld\n",
  546.                                  r, r->key, r->objectID, r->objectID);
  547.             r = (RefDataShadowEntryPtr)cmGetNextListCell(r);
  548.         }
  549.     } /* r */
  550.     #endif
  551.     
  552.     if (!cmIsEmptyList(&theValueHdr->valueList))
  553.         display(f, "\n");
  554.  
  555.     return (WalkNextTOCValue);
  556. }
  557.  
  558.  
  559. /*--------------------------------------------------------------*
  560.  | showValue - action routine for displaying a value in the TOC |
  561.  *--------------------------------------------------------------*
  562.  
  563.  This is a debugging routine used as the "action" parameter to cmWalkThroughEntireTOC()
  564.  calls to display selected info for a value in the TOC.  The "refCon" here is expected to
  565.  be a file variable.
  566.  
  567.  Note, this "static" is intentionally left to default memory model under DOS since it is
  568.  passed as a function pointer to cmWalkThroughEntireTOC().
  569. */
  570.  
  571. static TOCWalkReturns showValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
  572. {
  573.     ContainerPtr      unused = container;    
  574.     FILE                      *f = (FILE *)refCon;
  575.     CM_ULONG             i, value4, valueLen;
  576.     CM_USHORT             mask, flags;
  577.     CM_CHAR               *s, valueChars[5], flagsMeaning[256];
  578.     CM_UCHAR             *b;
  579.     
  580.     flags = theValue->flags;
  581. #if !CMKEEP_CONTINUE_FLAG
  582.     if (cmGetNextListCell(theValue))
  583.         flags |= kCMContinued;
  584.     else
  585.         flags &= ~kCMContinued;
  586. #endif
  587.     
  588.     if (flags == 0x0000U)
  589.         *flagsMeaning = '\0';
  590.     else {    
  591.         strcpy(flagsMeaning, " (");
  592.         
  593.         for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) {
  594.             if ((flags & mask) == kCMImmediate) {
  595.                 strcat(flagsMeaning, "kCMImmediate/");
  596.                 continue;
  597.             }
  598.             if ((flags & mask) == kCMContinued) {
  599.                 strcat(flagsMeaning, "kCMContinued/");
  600.                 continue;
  601.             }
  602.             if ((flags & mask) == kCMDynValue) {
  603.                 strcat(flagsMeaning, "kCMDynValue/");
  604.                 continue;
  605.             }
  606.             if ((flags & mask) == kCMGlobalName) {
  607.                 strcat(flagsMeaning, "kCMGlobalName/");
  608.                 continue;
  609.             }
  610.         } /* for */
  611.         
  612.         strcpy(flagsMeaning + strlen(flagsMeaning) - 1, ")");
  613.     }
  614.     
  615.     display(f, "                                    TOCValue\n"
  616.                          "                                    0x%.8lX: theValueHdr     = 0x%.8lX\n"
  617.                          "                                                flags           = 0x%.4X%s\n"
  618.                          "                                                container       = 0x%.8lX (%s) [%d]\n"
  619.                          "                                                logicalOffset   = 0x%.8lX = %ld\n",
  620.                          theValue,
  621.                          theValue->theValueHdr,
  622.                          theValue->flags, flagsMeaning,
  623.                          theValue->container, CONTAINERNAMEx(theValue->container), theValue->container->depth,
  624.                          theValue->logicalOffset, theValue->logicalOffset);
  625.                             
  626.     if (theValue->flags & kCMGlobalName)
  627.         display(f, "                                                offset          = 0x%.8lX\n"
  628.                              "                                                globalNameSymbol= 0x%.8lX\n"
  629.                              "                                                \"%s\"\n",
  630.                              theValue->value.globalName.offset, theValue->value.globalName.globalNameSymbol,
  631.                              theValue->value.globalName.globalNameSymbol ? GetGlobalName(theValue->value.globalName.globalNameSymbol)
  632.                                                                                                                       : "????");
  633.     else {
  634.         valueLen = theValue->value.notImm.valueLen;
  635.         value4   = theValue->value.notImm.value;
  636.         
  637.         if (flags & kCMImmediate) {
  638.             for (i = 0, b = (CM_UCHAR *)&value4, s = valueChars; i < valueLen; ++i, ++b)
  639.                 *s++ = (CM_CHAR)((*b < (CM_UCHAR)' ' ||  *b > (CM_UCHAR)126) ? '.' : (*b));
  640.             *s = '\0';
  641.             
  642.             if (valueLen == 1)
  643.                 value4 >>= 3 * CHAR_BIT;
  644.             else if (valueLen == 2)
  645.                 value4 >>= 2 * CHAR_BIT;
  646.             else  if (valueLen == 3)
  647.                 value4 >>= 1 * CHAR_BIT;
  648.             
  649.             display(f, "                                                value           = 0x%.*lX = '%s' = %ld\n"
  650.                                  "                                                length          = 0x%.8lX = %ld\n",
  651.                                  (int)(valueLen * 2), value4, valueChars, value4,
  652.                                  valueLen, valueLen);
  653.         } else
  654.             display(f, "                                                value           = 0x%.8lX = %ld\n"
  655.                                  "                                                length          = 0x%.8lX = %ld\n",
  656.                                  value4, value4,
  657.                                  valueLen, valueLen);
  658.     }
  659.     
  660.     return (WalkNextTOCValue);
  661. }
  662.  
  663.  
  664. /*-------------------------------------------------------------------------*
  665.  | CMDumpTOCStructures - dump all the TOC structures to the specified file |
  666.  *-------------------------------------------------------------------------*
  667.  
  668.  This routine is used for internal debugging of the TOC data structures for the specified
  669.  container.  It displays their current state to the (open) file associated with the
  670.  specified file variable, f.
  671. */
  672.  
  673. void CM_FIXEDARGS CMDumpTOCStructures(CMContainer container, FILE CM_PTR *f)
  674. {
  675.     display(f, "\nTOC for type \"%s\" (%s) [%d]...\n\n", TYPENAME, CONTAINERNAME, ((ContainerPtr)container)->depth);
  676.     cmWalkThroughEntireTOC((ContainerPtr)container, ((ContainerPtr)container)->toc,
  677.                                                     ALLOBJECTS, MAXUSERID, f,
  678.                                                     showObject, showProperty, showValueHdr, showValue);
  679.     
  680.     if (((ContainerPtr)container)->usingTargetTOC) {
  681.         display(f, "\n\nPrivate TOC for type \"%s\" (%s)...\n\n", TYPENAME, CONTAINERNAME);
  682.         cmWalkThroughEntireTOC((ContainerPtr)container, ((ContainerPtr)container)->privateTOC,
  683.                                                         ALLOBJECTS, MAXUSERID, f,
  684.                                                         showObject, showProperty, showValueHdr, showValue);
  685.     }
  686.     
  687.     display(f, "\n");
  688. }
  689.  
  690.  
  691. #if TOC1_SUPPORT
  692. /*-----------------------------------------------------------------------------*
  693.  | dumpContainerTOCfmt1 - dump the format 1 TOC as it appears in the container |
  694.  *-----------------------------------------------------------------------------*
  695.  
  696.  This routine is used for internal debugging of the format 1 TOC data as it appears in its
  697.  final form in the container itself.  The entire TOC in the container, starting at 
  698.  container offset tocOffset for tocSize bytes, is displayed to the (open) file associated
  699.  with the file variable f.  It is formatted, but otherwise unchanged.  You can use this
  700.  routine to see if the TOC was correctly written to its container.
  701.  
  702.  Note, the container's handler routines are used to do the positioning and reading.
  703. */
  704.  
  705. static void CM_NEAR dumpContainerTOCfmt1(CMconst_CMContainer container, FILE CM_PTR *f,
  706.                                                                                    const CM_ULONG tocOffset, const CM_ULONG tocSize)
  707. {    
  708.     CM_ULONG           objectID, propertyID, typeID;
  709.     TOCValueBytes  value;
  710.     CM_USHORT             generation, flags;
  711.     CM_UCHAR             tocBuffer[TOCentrySize];
  712.     CM_ULONG           size      = (CM_ULONG)tocSize,
  713.                                  offset    = (CM_ULONG)tocOffset,
  714.                                  relOffset = 0;
  715.     
  716.     display(f, "\nTOC for type \"%s\" (%s)...\n\n", TYPENAME, CONTAINERNAME);
  717.     
  718.     display(f, "              | objectID |propertyID|  typeID  |  value   |  length  | gen  |flags |\n"
  719.                          "              +----------+----------+----------+----------+----------+------+------+\n");
  720.     
  721.     /* Position to the start of the TOC...                                                                                                */
  722.     
  723.     CMfseek(container, tocOffset, kCMSeekSet);
  724.     
  725.     while (size > 0) {                                            /* for each entry in the container's TOC...        */
  726.         if (CMfread(container, tocBuffer, sizeof(CM_UCHAR), TOCentrySize) != TOCentrySize) {
  727.             display(f, "### Read error in cmDumpContainerTOC()\n");
  728.             return;
  729.         }
  730.         
  731.         ExtractTOC(tocBuffer, objectID, propertyID, typeID, value.notImm.value,
  732.                                                     value.notImm.valueLen, generation, flags);
  733.                 
  734.         display(f, "%.8lX:%.4lX | %.8lX | %.8lX | %.8lX | %.8lX | %.8lX | %.4X | %.4X |\n",
  735.                                          offset, relOffset, objectID, propertyID, typeID, value.notImm.value,
  736.                                          value.notImm.valueLen, generation, flags);
  737.         
  738.         offset    += TOCentrySize;
  739.         relOffset += TOCentrySize;
  740.  
  741.         size      -= TOCentrySize;                        /* count down the size                                                */
  742.     } /* while */
  743.  
  744.     display(f, "%.8lX:%.4lX +----------+----------+----------+----------+----------+------+------+\n\n",
  745.                           offset, relOffset);
  746. }
  747. #endif
  748.  
  749.  
  750. /*------------------------------------------------------------------*
  751.  | CMDumpContainerTOC - dump the TOC as it appears in the container |
  752.  *------------------------------------------------------------------*
  753.  
  754.  This routine is used for internal debugging of the TOC data as it appears in its final
  755.  form in the container itself.  The entire TOC in the container, starting at container
  756.  offset tocOffset for tocSize bytes, is displayed to the (open) file associated with the
  757.  file variable f.  It is formatted, but otherwise  unchanged.  You can use this routine to
  758.  see if the TOC was correctly written to its container.
  759.  
  760.  Note, the container's handler routines are used to do the positioning and reading.
  761. */
  762.  
  763. void CM_FIXEDARGS CMDumpContainerTOC(CMconst_CMContainer container, FILE CM_PTR *f,
  764.                                                                         const CM_ULONG tocOffset, const CM_ULONG tocSize)
  765. {    
  766.     TOCentry             tocEntry;
  767.     CM_ULONG           refsDataObjectID;
  768.     CM_ULONG             prevObjectID, prevPropertyID, prevTypeID;
  769.     CM_ULONG           offset, relOffset;
  770.     void                      *tocIOCtl;
  771.     jmp_buf                 dumpEnv;
  772.     
  773.     USE_TOC_FORMAT_1_ALTERNATIVE1(dumpContainerTOCfmt1,(container, f, tocOffset, tocSize));
  774.     
  775.     /* Display the format 2 TOC.  Information is not repeated if it it wasn't repeated in */
  776.     /* the actual TOC.                                                                                                                                        */
  777.     
  778.     if (setjmp(dumpEnv))                                         /* set setjmp/longjmp environment vector            */
  779.         return;                                                                /* ...just quit if there's a TOC input error    */
  780.  
  781.     /* Position to the start of the TOC...                                                                                                */
  782.     
  783.     CMfseek(container, tocOffset, kCMSeekSet);
  784.     
  785.     /* Create the TOC I/O control block and its buffer...                                                                    */
  786.     
  787.     tocIOCtl = cmStartTOCIO((ContainerPtr)container, ((ContainerPtr)container)->tocBufSize,
  788.                                                     (jmp_buf *)&dumpEnv, tocOffset, tocSize);
  789.     if (tocIOCtl == NULL) return;
  790.     
  791.     prevObjectID = prevPropertyID = prevTypeID = 0x00000000UL;
  792.     
  793.     display(f, "\nTOC for type \"%s\" (%s)...\n\n", TYPENAME, CONTAINERNAME);
  794.     
  795.     display(f, "              | objectID |propertyID|  typeID  |generation|  value   |  length  |flags |  Ref ID  |\n"
  796.                          "              +----------+----------+----------+----------+----------+----------+------+----------+\n");
  797.     
  798.     /* Read the entire TOC and display it in the following loop...                                                */
  799.     
  800.     while (cmRead1TOCSegment(tocIOCtl, &tocEntry, &refsDataObjectID)) {
  801.         offset = SESSION->currTOCoffset;
  802.         relOffset = offset - tocOffset;
  803.         display(f, "%.8lX:%.4lX ", offset, relOffset);
  804.         
  805.         if (tocEntry.objectID != prevObjectID) {
  806.             prevObjectID      = tocEntry.objectID;
  807.             prevPropertyID = tocEntry.propertyID;
  808.             prevTypeID        = tocEntry.typeID;
  809.             display(f, "| %.8lX | %.8lX | %.8lX | ", tocEntry.objectID, tocEntry.propertyID, tocEntry.typeID);
  810.         } else if (tocEntry.propertyID != prevPropertyID) {
  811.             prevPropertyID = tocEntry.propertyID;
  812.             prevTypeID     = tocEntry.typeID;
  813.             display(f, "|          | %.8lX | %.8lX | ", tocEntry.propertyID, tocEntry.typeID);
  814.         } else if (tocEntry.typeID != prevTypeID) {
  815.             prevTypeID = tocEntry.typeID;
  816.             display(f, "|          |          | %.8lX | ", tocEntry.typeID);
  817.         } else {
  818.             display(f, "|          |          |          | ");
  819.         }
  820.         
  821.         if (SESSION->gotExplicitGen) {
  822.             display(f, "%.8lX | ", tocEntry.generation);
  823.         } else
  824.             display(f, "         | ");
  825.         
  826.         display(f, "%.8lX | %.8lX | %.4X | ", tocEntry.value.notImm.value, tocEntry.value.notImm.valueLen, tocEntry.flags);
  827.         
  828.         if (refsDataObjectID == 0x00000000UL)
  829.             display(f, "         |\n");
  830.         else
  831.             display(f, "%.8lX |\n", refsDataObjectID);
  832.     } /* while */
  833.     
  834.     offset = SESSION->currTOCoffset;
  835.     relOffset = offset - tocOffset;
  836.     display(f, "%.8lX:%.4lX +----------+----------+----------+----------+----------+----------+------+----------+\n\n",
  837.                             offset, relOffset);
  838.     
  839.     (void)cmEndTOCIO(tocIOCtl);
  840. }
  841. #endif 
  842.                                                           CM_END_CFUNCTIONS
  843.